package ext.acae2.dms.load;

import java.util.ArrayList;

import org.apache.log4j.Logger;

import com.ptc.core.meta.type.mgmt.server.impl.WTTypeDefinition;

import wt.build.BuildHelper;
import wt.build.BuildReference;
import wt.doc.WTDocument;
import wt.doc.WTDocumentMaster;
import wt.epm.EPMDocument;
import wt.epm.EPMDocumentMaster;
import wt.epm.build.EPMBuildHistory;
import wt.epm.build.EPMBuildRule;
import wt.epm.interfaces.EPMDependencyMaster;
import wt.epm.structure.EPMDescribeLink;
import wt.epm.structure.EPMMemberLink;
import wt.epm.structure.EPMReferenceLink;
import wt.epm.structure.EPMReferenceType;
import wt.epm.structure.EPMStandardStructureService;
import wt.fc.PersistenceHelper;
import wt.fc.PersistenceServerHelper;
import wt.fc.QueryResult;
import wt.fc.ReferenceFactory;
import wt.log4j.LogR;
import wt.occurrence.UsesOccurrence;
import wt.part.BuildStatus;
import wt.part.PartUsesOccurrence;
import wt.part.Quantity;
import wt.part.QuantityUnit;
import wt.part.WTPart;
import wt.part.WTPartMaster;
import wt.part.WTPartReferenceLink;
import wt.part.WTPartUsageLink;
import wt.query.QuerySpec;
import wt.query.SearchCondition;
import wt.type.TypeDefinitionForeignKey;
import wt.type.TypeDefinitionReference;
import wt.util.WTException;
import wt.util.WTPropertyVetoException;
import ext.acae2.dms.bean.DataBean;
import ext.acae2.dms.bean.DocumentBean;
import ext.acae2.dms.bean.EPMBuildHistoryBean;
import ext.acae2.dms.bean.EPMBuildRuleBean;
import ext.acae2.dms.bean.EPMDocumentBean;
import ext.acae2.dms.bean.EPMMemberLinkBean;
import ext.acae2.dms.bean.EPMReferenceLinkBean;
import ext.acae2.dms.bean.PartBean;
import ext.acae2.dms.bean.PartUsageLinkBean;
import ext.acae2.util.QueryUtil;
import ext.acae2.util.SoftTypeUtil;
import ext.acae2.utilities.docpart.CSCPart;

public class LinkFactory {
	
    private static final Logger LOGGER = LogR.getLogger(LinkFactory.class.getName());
    
    private static LinkFactory factory = null;
    
    private LinkFactory() {}
    
    /**
     * Singleton Pattern to get factory
     * 
     * @return factory
     */
    public static synchronized LinkFactory getInstance() {
        if (factory == null) {
            factory = new LinkFactory();
        }
        return factory;
    }
    
    public void createLink(DataBean bean01, DataBean bean02) throws WTException {
    	LOGGER.debug("> Start createLink");
    	
    	if (bean01 instanceof PartBean) {
    		
    		if (bean02 instanceof PartBean) {
        		createPartUsageLink(bean01, bean02);
        	}
        	
        	if (bean02 instanceof EPMDocumentBean) {
        		createEPMDescribeLink(bean01, bean02);
        	}
        	
        	if (bean02 instanceof DocumentBean) {
        		createWTPartReferenceLink(bean01, bean02);
        	}
        	
    	}
    	
    	LOGGER.debug("> End createLink");
    }
    
    public void createLink(Object obj) throws WTPropertyVetoException, WTException{
    	if(obj instanceof EPMMemberLinkBean){
    		EPMMemberLinkBean memberLinkBean = (EPMMemberLinkBean)obj;
    		createEPMMemberLink(memberLinkBean);
    	}else if(obj instanceof EPMBuildRuleBean){
    		EPMBuildRuleBean buildRuleBean =(EPMBuildRuleBean)obj;
    		createEPMBuildRule(buildRuleBean);
    	}else if(obj instanceof EPMReferenceLinkBean){
    		EPMReferenceLinkBean refLink = (EPMReferenceLinkBean)obj;
    		createEPMRefLink(refLink);
    	}else if(obj instanceof PartUsageLinkBean){
    		PartUsageLinkBean partUsageLinkBean = (PartUsageLinkBean)obj;
    		createWTPartUsageLink(partUsageLinkBean);
    	}
    }
    
    private void createWTPartUsageLink(PartUsageLinkBean usageLinkBean){
    	
    	LOGGER.debug("> Start createPartUsageLink");
    	try{
    		PartBean parentPartBean = usageLinkBean.getParentPart();
        	PartBean childPartBean = usageLinkBean.getChildPart();
        	double singleAmout = usageLinkBean.getSingleAmout();

    		// get ParentPart ChildPart number toUpperCase!!!!
    		String parentPartNumber = parentPartBean.getNumber().toUpperCase();
    		String childPartNumber = childPartBean.getNumber().toUpperCase();

    		WTPart parentPart = QueryUtil.getPartByNumber(parentPartNumber);
    		WTPart childPart = QueryUtil.getPartByNumber(childPartNumber);

    		if (DmsLoadSearchHelper.searchWTPartUsageLink(parentPart,
    				(WTPartMaster) childPart.getMaster()) == null) {

    			// add WTPartUsageLink
    			WTPartUsageLink link = WTPartUsageLink.newWTPartUsageLink(
    					parentPart, (WTPartMaster) childPart.getMaster());
    			Quantity qu = Quantity.newQuantity();
    			qu.setAmount(singleAmout);
    			qu.setUnit(QuantityUnit.EA);
    			link.setQuantity(qu);
    			PersistenceServerHelper.manager.insert(link);
    		}
    	}catch(Exception e){
    		e.printStackTrace();
    	}
    	
		LOGGER.debug("> End createPartUsageLink");
    	
    }
    
    private void createEPMRefLink(EPMReferenceLinkBean refLinkBean) throws WTException, WTPropertyVetoException{
    	String epmDocNumber = refLinkBean.getEpmBean().getNumber().toUpperCase();
    	String refEpmNumber = refLinkBean.getRefEpmBean().getNumber().toUpperCase();
    	EPMDocument epmDoc = QueryUtil.getEPMDocumentByNumber(epmDocNumber);
    	EPMDocument refEpmDoc = QueryUtil.getEPMDocumentByNumber(refEpmNumber);
    	
    	if(DmsLoadSearchHelper.searchEPMReferenceLink(epmDoc, (EPMDocumentMaster)refEpmDoc.getMaster())==null){
    		long typeId = epmDoc.getTypeDefinitionReference().getKey().getId();
        	long typeBranchId = epmDoc.getTypeDefinitionReference().getKey().getBranchId();
        	
        	long epmlinkID = EPMStandardStructureService.getNextEPMLinkSequence();
        	
        	LOGGER.debug(typeId+"======================"+typeBranchId);
        	
        	LOGGER.debug(epmlinkID+"===========createEPMRefLink==========="+epmlinkID);
        	
        	typeId = refEpmDoc.getTypeDefinitionReference().getKey().getId();
        	typeBranchId = refEpmDoc.getTypeDefinitionReference().getKey().getBranchId();
        	
        	EPMReferenceLink refLink = EPMReferenceLink.newEPMReferenceLink(epmDoc, (EPMDocumentMaster)refEpmDoc.getMaster());
        	refLink.setAsStoredChildName(refEpmDoc.getCADName());
        	refLink.setReferenceType(EPMReferenceType.toEPMReferenceType("DRAWING"));
        	refLink.setDepType(4);
        	refLink.setRequired(true);
        	refLink.setUniqueLinkID(epmlinkID);
        	
        	refLink.setUniqueNDId("R/4/"+refEpmDoc.getCADName()+"/1");
        	PersistenceServerHelper.manager.insert(refLink);
    	}
    	
    	
    }
    
//    private void createEPMBuildHistory(EPMBuildHistoryBean buildHisBean){
//    	IxbHndHelper.findAlreadyImportedV2VLink(EPMBuildRule.class, arg1, arg2)
//    }
    
    
	private void createEPMBuildRule(EPMBuildRuleBean buildRuleBean)
			throws WTException, WTPropertyVetoException {
		String partNumber = buildRuleBean.getPart().getNumber().toUpperCase();
		String epmDocNumber = buildRuleBean.getEpmDocument().getNumber()
				.toUpperCase();

		WTPart part = QueryUtil.getPartByNumber(partNumber);
		EPMDocument epmDoc = QueryUtil.getEPMDocumentByNumber(epmDocNumber);
		
		EPMBuildRule exitEpmBuildRule = DmsLoadSearchHelper.searchEPMBuildRule(epmDoc, part);
		
		if (exitEpmBuildRule == null) {
			EPMBuildRule buildRule = EPMBuildRule.newEPMBuildRule(epmDoc, part);
			buildRule.setBuildType(7);
			buildRule.setAttributes(EPMBuildRule.ATTRIBUTE_ON_LINK, 2);
			buildRule.setAttributes(EPMBuildRule.ATTRIBUTE_ON_MASTER, 2);
			buildRule.setAttributes(EPMBuildRule.ATTRIBUTE_ON_OCCURRENCE, 2);
			buildRule.setAttributes(EPMBuildRule.ATTRIBUTE_ON_TARGET, 2);

			long buildRuleId = EPMStandardStructureService
					.getNextEPMLinkSequence();

			buildRule.setUniqueID(buildRuleId);

			PersistenceServerHelper.manager.insert(buildRule);
			exitEpmBuildRule = buildRule; //不存在的情况下完成创建并将创建好的buildrule赋给存在buildHis
			
//			if(buildRuleBean.getParentPart()!=null){
//				String parentPartNumber = buildRuleBean.getParentPart().getNumber();
//				
//				String parentEpmNumber = buildRuleBean.getParentEpmBean().getNumber();
//				
//				EPMDocument parentEpm = QueryUtil.getEPMDocumentByNumber(parentEpmNumber);
//
//				WTPart parentPart = QueryUtil.getPartByNumber(parentPartNumber);
//
//				WTPartUsageLink usageLink = DmsLoadSearchHelper
//						.searchWTPartUsageLink(parentPart,
//								(WTPartMaster) part.getMaster());
//				
//				EPMMemberLink memberLink = DmsLoadSearchHelper.searchEPMMemberLink(parentEpm, (EPMDocumentMaster) epmDoc.getMaster(), 1);
//				
//				PartUsesOccurrence partusesoccurrence = PartUsesOccurrence.newPartUsesOccurrence(usageLink);
//				
//				BuildReference buildreference = BuildReference.newBuildReference(buildRule.getApplicationTag(), String.valueOf(memberLink.getUniqueLinkID()));
//				
//				partusesoccurrence.setSourceIdentification(buildreference);
//				partusesoccurrence.setBuildStatus(BuildStatus.BUILT);
//				PersistenceServerHelper.manager.insert(partusesoccurrence);
//				
////				String s = buildRule.getApplicationTag();
////				LOGGER.debug(s+"===========getApplicationTag()==========="+s);
////				String s1 = String.valueOf(usageLink.getPersistInfo().getObjectIdentifier().getId());
////				LOGGER.debug(s1 + "===========getObjectIdentifier()==========="
////						+ s1);
////			    String s2 = s1 + "&&" + usageLink.getQuantity().getUnit();
////				BuildReference buildreference = BuildReference.newBuildReference(s, s2);   
////				usageLink.setSourceIdentification(buildreference);
////				PersistenceServerHelper.manager.update(usageLink);
////				usageLink = (WTPartUsageLink)PersistenceHelper.manager.refresh(usageLink);
////				PartUsesOccurrence partusesoccurrence = getNamedOccurrence(usageLink, s);
////				if (partusesoccurrence != null){
////					BuildHelper.markAsBuilt(partusesoccurrence, buildreference);
////				}
////				PersistenceServerHelper.manager.update(partusesoccurrence);
//			}

			

		}
		/**buildHis create add by cnie 20130624 begin**/
		EPMBuildHistory buildHis = DmsLoadSearchHelper.searchEPMBuildHistory(epmDoc, part);
		if(buildHis==null){
			long buildRuleId = exitEpmBuildRule.getUniqueID();
			int buildType = exitEpmBuildRule.getBuildType();
			EPMBuildHistory epmBuildHis = EPMBuildHistory.newEPMBuildHistory(
					epmDoc, part, buildType);
			epmBuildHis.setBuildRuleID(buildRuleId);
			PersistenceServerHelper.manager.insert(epmBuildHis);
		}
		/**buildHis create add by cnie 20130624 end**/	

	}
    
    
    private void createEPMMemberLink(EPMMemberLinkBean memberLinkBean)throws WTException, WTPropertyVetoException{
    	String parentEpmNumber = memberLinkBean.getParentEpm().getNumber().toUpperCase();
    	String childEpmNumber = memberLinkBean.getChildEpm().getNumber().toUpperCase();
    	EPMDocument parentEpm = QueryUtil.getEPMDocumentByNumber(parentEpmNumber);
    	EPMDocument childEpm = QueryUtil.getEPMDocumentByNumber(childEpmNumber);
    	int memberCount = memberLinkBean.getMemberCount();
    	if(DmsLoadSearchHelper.searchEPMMemberLink(parentEpm, (EPMDocumentMaster) childEpm.getMaster(), 1)==null){
    		for(int i=0;i<memberCount;i++){   //modify by cnie for memberLink
    			EPMMemberLink epmLink = EPMMemberLink.newEPMMemberLink(parentEpm, (EPMDependencyMaster) childEpm.getMaster());
            	Quantity quantity = Quantity.newQuantity(memberLinkBean.getSingleAmout(), QuantityUnit.EA);
            	epmLink.setQuantity(quantity);
            	epmLink.setAsStoredChildName(childEpm.getCADName());
            	epmLink.setAnnotated(false);
            	epmLink.setPlaced(true);
            	epmLink.setRequired(true);
            	long epmlinkID = EPMStandardStructureService.getNextEPMLinkSequence();
            	WTTypeDefinition typeDe = SoftTypeUtil.getSoftType("com.acae.DefaultEPMMemberLink");
            	TypeDefinitionReference typeRef=TypeDefinitionReference.newTypeDefinitionReference();
            	TypeDefinitionForeignKey forKey = TypeDefinitionForeignKey.newTypeDefinitionForeignKey();
            	forKey.setBranchId(typeDe.getIterationInfo().getBranchId());
            	forKey.setId(typeDe.getPersistInfo().getObjectIdentifier().getId());
            	typeRef.setKey(forKey);
            	epmLink.setTypeDefinitionReference(typeRef);
            	LOGGER.debug(epmlinkID+"========================epmlinkID");
            	
            	epmLink.setUniqueLinkID(epmlinkID);
            	epmLink.setIdentifierSpaceName("UG");
            	epmLink.setDepType(2);
            	PersistenceServerHelper.manager.insert(epmLink);
    		}
    	}
    	
    }
    
    /**
     * Method to create PartUsageLink according to parentPart and childPart.
     * 
     * @param parentPart
     * @param childPart
     * @return
     * @throws WTException
     */
	private void createPartUsageLink(DataBean parentPartBean,
			DataBean childPartBean) throws WTException {
		LOGGER.debug("> Start createPartUsageLink");

		// get ParentPart ChildPart number toUpperCase!!!!
		String parentPartNumber = parentPartBean.getNumber().toUpperCase();
		String childPartNumber = childPartBean.getNumber().toUpperCase();

		WTPart parentPart = QueryUtil.getPartByNumber(parentPartNumber);
		WTPart childPart = QueryUtil.getPartByNumber(childPartNumber);

		if (DmsLoadSearchHelper.searchWTPartUsageLink(parentPart,
				(WTPartMaster) childPart.getMaster()) == null) {

			// add WTPartUsageLink
			WTPartUsageLink link = WTPartUsageLink.newWTPartUsageLink(
					parentPart, (WTPartMaster) childPart.getMaster());
			PersistenceServerHelper.manager.insert(link);
		}
		LOGGER.debug("> End createPartUsageLink");
	}
	
	 /**
     * Method to create EPMDescribeLink according to part and epmDoc.
     * 
     * @param part
     * @param epmDoc
     * @return
     * @throws WTException
     */
	@SuppressWarnings("rawtypes")
	private void createEPMDescribeLink(DataBean partBean, DataBean epmDocBean) throws WTException {
		LOGGER.debug("> Start createEPMDescribeLink");
		
		//get ParentPart ChildPart *************************************************
		String partNumber = partBean.getNumber().toUpperCase();
		String epmDocNumber = epmDocBean.getNumber().toUpperCase();
		
		WTPart part = QueryUtil.getPartByNumber(partNumber);
		EPMDocument epmDoc = QueryUtil.getEPMDocumentByNumber(epmDocNumber);
		
		ArrayList described = CSCPart.getDescribedDocumentsByPart(part);
		boolean b = described.contains((EPMDocument)epmDoc);
		if(!b){
			//add EPMDescribeLink
			EPMDescribeLink link = EPMDescribeLink.newEPMDescribeLink(part, epmDoc);
			PersistenceServerHelper.manager.insert(link);
		}
		
		LOGGER.debug("> End createEPMDescribeLink");
	}
	
	 /**
     * Method to create WTPartReferenceLink according to part and doc.
     * 
     * @param part
     * @param doc
     * @return
     * @throws WTException
     */
	private void createWTPartReferenceLink(DataBean partBean, DataBean docBean) throws WTException {
		LOGGER.debug("> Start createWTPartReferenceLink");
		
		//get ParentPart ChildPart ***************************************************
		String partNumber = partBean.getNumber().toUpperCase();
		String docNumber = docBean.getNumber().toUpperCase();
		
		WTPart part = QueryUtil.getPartByNumber(partNumber);
		WTDocument doc = QueryUtil.getDocumentByNumber(docNumber);
			
		//remove link
		removeReferenceLink(part, doc);
		//add WTPartReferenceLink
		WTPartReferenceLink link = WTPartReferenceLink.newWTPartReferenceLink(part, (WTDocumentMaster)doc.getMaster());
		
		PersistenceServerHelper.manager.insert(link);
		
		LOGGER.debug("> End createWTPartReferenceLink");
	}
	
	/**
     * @param part
     * 
     * @throws WTException
     */
	public void removeEpmDescribeLink(WTPart part) throws WTException
	{
		LOGGER.debug("> Start removeEpmDescribeLink");
		
		QueryResult qr = PersistenceHelper.manager.navigate(part,EPMDescribeLink.DESCRIBED_BY_ROLE, EPMDescribeLink.class,false);
		EPMDescribeLink epmDesc = null;
		while(qr.hasMoreElements())
		{
			epmDesc = (EPMDescribeLink)qr.nextElement(); 
			PersistenceServerHelper.manager.remove(epmDesc);
		}
		
		LOGGER.debug("> End removeEpmDescribeLink");
	}
	
	/**
     * @param part
     * 
     * @throws WTException
     */
	public void removeEpmDescribeLink(EPMDocument document) throws WTException
	{
		LOGGER.debug("> Start removeEpmDescribeLink");
		
		QueryResult qr = PersistenceHelper.manager.navigate(document,EPMDescribeLink.DESCRIBES_ROLE, EPMDescribeLink.class,false);
		EPMDescribeLink epmDesc = null;
		while(qr.hasMoreElements())
		{
			epmDesc = (EPMDescribeLink)qr.nextElement(); 
			PersistenceServerHelper.manager.remove(epmDesc);
		}
		
		LOGGER.debug("> End removeEpmDescribeLink");
	}
	
	/**
     * @param part
     * 
     * @throws WTException
     */
	public void removeUsageLink(WTPart part) throws WTException
	{
		LOGGER.debug("> Start removeUsageLink");
		
		QueryResult qr = PersistenceHelper.manager.navigate(part,WTPartUsageLink.USES_ROLE, WTPartUsageLink.class,false);
		WTPartUsageLink partUsage = null;
		while(qr.hasMoreElements())
		{
			partUsage = (WTPartUsageLink)qr.nextElement(); 
			PersistenceServerHelper.manager.remove(partUsage);
		}
		
		LOGGER.debug("> End removeUsageLink");
	}
	
	/**
	 * not excute
     * @param part
     * 
     * @throws WTException
     */
	public void removeReferenceLink(WTDocument document) throws WTException
	{
		QueryResult qr = PersistenceHelper.manager.navigate(document,WTPartReferenceLink.REFERENCES_ROLE, WTPartReferenceLink.class,false);
		WTPartReferenceLink partReference = null;
		while(qr.hasMoreElements())
		{
			partReference = (WTPartReferenceLink)qr.nextElement(); 
			PersistenceServerHelper.manager.remove(partReference);
		}
	}
	
	public static WTPartReferenceLink getPartReferenceLink(WTPart wtpart, WTDocument wtdocument) throws WTException{
		QueryResult queryresult = PersistenceHelper.manager.find(wt.part.WTPartReferenceLink.class, wtpart,
				WTPartReferenceLink.REFERENCED_BY_ROLE, (WTDocumentMaster)wtdocument.getMaster());
		if (queryresult == null || queryresult.size() == 0)
			return null;
		else
			return (WTPartReferenceLink) queryresult.nextElement();
	}
	
	public void removeReferenceLink(WTPart wtpart, WTDocument wtdocument) throws WTException {
		LOGGER.debug("> Start removeReferenceLink");
		
		QueryResult queryresult = PersistenceHelper.manager.find(wt.part.WTPartReferenceLink.class, wtpart,
				WTPartReferenceLink.REFERENCED_BY_ROLE, (WTDocumentMaster)wtdocument.getMaster());
		WTPartReferenceLink partReference = null;
		while(queryresult.hasMoreElements())
		{
			partReference = (WTPartReferenceLink)queryresult.nextElement(); 
			PersistenceServerHelper.manager.remove(partReference);
		}
		
		LOGGER.debug("> End removeReferenceLink");
	}
	
}
